defmodule EliPhxPlay.ChatSchema.UsersTest do
  use EliPhxPlay.DataCase

  alias EliPhxPlay.ChatSchema.Users
  alias EliPhxPlay.Repo

  describe "users schema" do
    @valid_attrs %{
      account: "test_user_001",
      password: "password123",
      nickname: "测试用户",
      avatar_url: "https://example.com/avatar.jpg",
      status: "active"
    }

    @invalid_attrs %{
      account: nil,
      password: nil,
      nickname: nil
    }

    test "changeset 使用有效属性时应该成功" do
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert changeset.valid?
    end

    test "changeset 缺少必填字段时应该失败" do
      changeset = Users.changeset(%Users{}, @invalid_attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).account
      assert "can't be blank" in errors_on(changeset).password
      assert "can't be blank" in errors_on(changeset).nickname
    end

    test "changeset 缺少 account 时应该失败" do
      attrs = Map.delete(@valid_attrs, :account)
      changeset = Users.changeset(%Users{}, attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).account
    end

    test "changeset 缺少 password 时应该失败" do
      attrs = Map.delete(@valid_attrs, :password)
      changeset = Users.changeset(%Users{}, attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).password
    end

    test "changeset 缺少 nickname 时应该失败" do
      attrs = Map.delete(@valid_attrs, :nickname)
      changeset = Users.changeset(%Users{}, attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).nickname
    end

    test "changeset 没有 avatar_url 时应该成功（可选字段）" do
      attrs = Map.delete(@valid_attrs, :avatar_url)
      changeset = Users.changeset(%Users{}, attrs)
      assert changeset.valid?
    end

    test "创建用户到数据库应该成功" do
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert {:ok, user} = Repo.insert(changeset)

      assert user.account == "test_user_001"
      assert user.nickname == "测试用户"
      assert user.status == "active"
      assert user.avatar_url == "https://example.com/avatar.jpg"
      assert is_binary(user.user_id)  # 验证 UUID 生成
    end

    test "用户默认状态应该是 active" do
      attrs = Map.delete(@valid_attrs, :status)
      changeset = Users.changeset(%Users{}, attrs)
      assert {:ok, user} = Repo.insert(changeset)
      assert user.status == "active"
    end

    test "更新用户信息应该成功" do
      # 先创建用户
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert {:ok, user} = Repo.insert(changeset)

      # 更新用户信息
      update_attrs = %{
        nickname: "更新后的昵称",
        status: "inactive"
      }

      update_changeset = Users.changeset(user, update_attrs)
      assert {:ok, updated_user} = Repo.update(update_changeset)

      assert updated_user.nickname == "更新后的昵称"
      assert updated_user.status == "inactive"
      assert updated_user.account == user.account  # 原有字段不变
    end

    test "status_until 字段应该可以设置" do
      future_time = ~N[2025-12-31 23:59:59]
      attrs = Map.put(@valid_attrs, :status_until, future_time)

      changeset = Users.changeset(%Users{}, attrs)
      assert {:ok, user} = Repo.insert(changeset)
      assert user.status_until == future_time
    end
  end

  describe "用户关联测试" do
    setup do
      # 创建测试用户
      user_attrs = %{
        account: "test_user_for_associations",
        password: "password123",
        nickname: "关联测试用户"
      }

      changeset = Users.changeset(%Users{}, user_attrs)
      {:ok, user} = Repo.insert(changeset)

      %{user: user}
    end

    test "用户应该有 sent_messages 关联", %{user: user} do
      # 验证关联存在但为空
      user_with_messages = Repo.preload(user, :sent_messages)
      assert user_with_messages.sent_messages == []
    end

    test "用户应该有 owned_groups 关联", %{user: user} do
      user_with_groups = Repo.preload(user, :owned_groups)
      assert user_with_groups.owned_groups == []
    end

    test "用户应该有 group_members 关联", %{user: user} do
      user_with_members = Repo.preload(user, :group_members)
      assert user_with_members.group_members == []
    end

    test "用户应该有 user_relationships_a 关联", %{user: user} do
      user_with_relations = Repo.preload(user, :user_relationships_a)
      assert user_with_relations.user_relationships_a == []
    end

    test "用户应该有 user_relationships_b 关联", %{user: user} do
      user_with_relations = Repo.preload(user, :user_relationships_b)
      assert user_with_relations.user_relationships_b == []
    end
  end

  describe "边界条件测试" do
    test "空字符串字段应该被验证为无效" do
      attrs = %{
        account: "",
        password: "",
        nickname: ""
      }

      changeset = Users.changeset(%Users{}, attrs)
      refute changeset.valid?
    end

    test "只有空格的字段应该被验证为无效" do
      attrs = %{
        account: "   ",
        password: "   ",
        nickname: "   "
      }

      changeset = Users.changeset(%Users{}, attrs)
      refute changeset.valid?
    end

    test "超长字段测试" do
      long_string = String.duplicate("a", 1000)
      attrs = %{
        account: long_string,
        password: "password123",
        nickname: "测试用户"
      }

      changeset = Users.changeset(%Users{}, attrs)
      # 注意：这里可能需要根据您的数据库字段长度限制来调整测试
      # 如果数据库有长度限制，这个测试可能会失败
    end
  end

  describe "主键和时间戳测试" do
    test "用户创建时应该自动生成 UUID 主键" do
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert {:ok, user} = Repo.insert(changeset)

      assert is_binary(user.user_id)
      assert String.length(user.user_id) == 36  # UUID 长度
    end

    test "用户创建时应该自动设置时间戳" do
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert {:ok, user} = Repo.insert(changeset)

      assert user.inserted_at != nil
      assert user.updated_at != nil
      assert user.inserted_at == user.updated_at  # 创建时两个时间相同
    end

    test "用户更新时应该更新 updated_at" do
      # 创建用户
      changeset = Users.changeset(%Users{}, @valid_attrs)
      assert {:ok, user} = Repo.insert(changeset)
      original_updated_at = user.updated_at

      # 等待一小段时间确保时间戳不同
      :timer.sleep(1000)

      # 更新用户
      update_changeset = Users.changeset(user, %{nickname: "新昵称"})
      assert {:ok, updated_user} = Repo.update(update_changeset)

      assert updated_user.inserted_at == user.inserted_at  # 创建时间不变
      assert NaiveDateTime.compare(updated_user.updated_at, original_updated_at) == :gt  # 更新时间变大
    end
  end
end
